import Router from 'koa-router';
import fs from 'mz/fs';
import ejs from 'ejs';
import path from 'path';
import util from 'util';
import querystring from 'querystring';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {matchRoutes, renderRoutes} from 'react-router-config';
import {StaticRouter} from 'react-router-dom';
import {Provider} from 'react-redux';

import utils from '../../src/utils';
import routes from '../../src/routes';
import * as config from '../../src/config';
import configStore from '../../src/redux/createStore';

const serverRenderRouter = new Router();

serverRenderRouter.get('*', async (ctx, next) => {
    // prepare for read param
    const store = configStore({}, {ctxCookie: ctx.header.cookie});
    const location = ctx.originalUrl.replace(config.appDomain, '') || '/';
    const query = location.indexOf('?') > -1
        ? querystring.parse(location.slice(location.indexOf('?') + 1))
        : {};

    const promises = utils.getDataPromises(store.dispatch, location, routes, {ctxCookie: ctx.header.cookie, query});

    ctx.type = 'text/html';
    ctx.body = await read(store, promises, location);
});


/**
 * render the final body after react’s server side render and ejs's tmpl
 *
 * @param {Store} store redux's store
 * @param {array} branch matchRoutes
 * @param {string} location link to
 * @return {string} body
 */
async function read(store, promises, location) {

    let initView;
    let state;
    let tmpl;
    const context = {}

    // get all data from server, prepare for store
    global.logger.info('[webnode] Promises length: %j', promises.length);
    try {
        await Promise.all(promises);
        state = JSON.stringify(store.getState());
        global.logger.debug('fetched fetchComponentData');
    }
    catch (err) {
        global.logger.error('[webnode api] Cannot get server-render data in fetchComponentData: %j', err, err.stack);
        state = JSON.stringify({});
    }

    // renderToString
    try {
        initView = renderToString(
            <Provider store={store}>
                <StaticRouter location={location} context={context}>
                    {renderRoutes(routes)}
                </StaticRouter>
            </Provider>
        );
    }
    catch (err) {
        global.logger.error('[rendertostring error]: %j - %s - %s ', util.inspect(err), err.stack);
    }

    // get template
    try {
        state = JSON.stringify(store.getState());
        tmpl = await fs.readFile(path.join(__dirname, '../../views/index.app.ejs'), 'utf-8');
    }
    catch (err) {
        global.logger.error('[get template error]: %j - %s', util.inspect(err), err.stack);
    }

    // inject initView and initState to teml
    return ejs.render(tmpl, {
        title: utils.getHTMLTitle(location, store.getState()),
        initialState: state,
        html: initView
    });
}

export default serverRenderRouter;
